﻿using System;
using System.IO;
using System.Xml.Linq;
using VsxFactory.Modeling.VisualStudio;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.TextManager.Interop;

namespace VsxFactory.Modeling.Strategies.Rules
{
    public abstract class ConfigFileRule : NodeGenerationRule
    {
        public ConfigFileRule(Type melType) : base(melType)
        {
            OverwriteFile = false;
        }

        protected abstract void GenerateElements(IStrategyContext context, GenerationSpec element, XElement doc);
        protected abstract void RemoveElements(IStrategyContext context, GenerationSpec element, XElement doc, string oldName);

        public override bool Generate(IStrategyContext context, GenerationSpec element, IVsProjectFileItem node)
        {
            if (base.Generate(context, element, node))
            {
                var doc = LoadConfigFile(Node);
                RemoveElements(context, element, doc, null);
                GenerateElements(context, element, doc);
                SaveConfigFile(doc, Node);
                return true;
            }
            return false;
        }

        public override void Remove(IStrategyContext context, GenerationSpec wrapper)
        {
            var node = GetCurrentNode(context, wrapper);
            if (node != null)
            {
                var doc = LoadConfigFile(node);
                RemoveElements(context, wrapper, doc, null);
                SaveConfigFile(doc, node);
            }
        }

        public override void Change(IStrategyContext context, GenerationSpec candidateElement, GenerationSpec targetElement, Guid propertyId, object oldValue)
        {
            if (base.Generate(context, targetElement, null))
            {
                var doc = LoadConfigFile(Node);
                string oldName = null;
                if (propertyId == candidateElement.NamePropertyId)
                    oldName = oldValue as string;
                RemoveElements(context, targetElement, doc, oldName);
                GenerateElements(context, targetElement, doc);
                SaveConfigFile(doc, Node);
            }
        }

        protected override string CalculateFileName(IVsProject project, GenerationSpec wrapper, string name = null)
        {
            string outputFileNameFormat = project.Kind == ProjectKind.WebApplication || project.Kind == ProjectKind.WebSite ? "web.config" : "app.config";
            return String.Format(outputFileNameFormat, Utils.NormalizeName(name ?? wrapper.Name));
        }

        protected XElement LoadConfigFile(IVsProjectFileItem node)
        {
            var content = node.GetContent();
                return System.Xml.Linq.XElement.Parse(content);
        }

        protected override IVsProjectFileItem OnOutputFileDoesntExist(IVsProject project, string fullName)
        {
            if (!File.Exists(fullName))
            {
                string templateFileName = GetConfigFileName(project);
                return project.AddFromTemplate(templateFileName, Path.GetFileName( fullName), false);
            }
            else
            {
                return project.AddItem(fullName);
            }
        }

        /// <summary>
        /// Gets the text from vs text lines.
        /// </summary>
        /// <param name="vsTextLines">The vs text lines.</param>
        /// <returns></returns>
        private static string GetTextFromVsTextLines(IVsTextLines vsTextLines)
        {
            int num;
            int num2;
            string str;
            ErrorHandler.ThrowOnFailure(vsTextLines.GetLineCount(out num));
            ErrorHandler.ThrowOnFailure(vsTextLines.GetLengthOfLine(num - 1, out num2));
            ErrorHandler.ThrowOnFailure(vsTextLines.GetLineText(0, 0, num - 1, num2, out str));
            return str;
        }

        protected void SaveConfigFile(XElement doc, IVsProjectFileItem node)
        {
            StringWriter sw = new StringWriter();
            doc.Save(sw);
            string result = sw.ToString();
            node.ReplaceText(result);
        }

        /// <summary>
        /// Gets the name of the config file.
        /// </summary>
        /// <returns></returns>
        private string GetConfigFileName(IVsProject project)
        {
            EnvDTE80.Solution2 solution = project.Solution.ExternalObject as EnvDTE80.Solution2;

            if (project.Kind == ProjectKind.WebApplication)
            {
                if (project.Language == "{B5E9BD34-6D3E-4B5D-925E-8A43B79820B4}") //EnvDTE.CodeModelLanguageConstants.vsCMLanguageCSharp)
                    return solution.GetProjectItemTemplate("webconfig.zip", "{349C5853-65DF-11DA-9384-00065B846F21}");
                else
                    return solution.GetProjectItemTemplate("webconfig.zip", "{349C5854-65DF-11DA-9384-00065B846F21}");
            }

            if (project.Kind == ProjectKind.WebSite)
                return solution.GetProjectItemTemplate("webconfig.zip", project.Language);

            if (project.Language == "{B5E9BD34-6D3E-4B5D-925E-8A43B79820B4}") //EnvDTE.CodeModelLanguageConstants.vsCMLanguageCSharp)
                return solution.GetProjectItemTemplate("appconfiginternal.zip", project.Language);
            else
                return solution.GetProjectItemTemplate("appconfigurationInternal.zip", project.Language);
        }
    }
}
